﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Graphix.Charts.Base
{
    using System.Drawing;
    using System.Globalization;
    using System.Reflection;

    using CommonHelpers;

    using Graphix.Elements;
    using Graphix.Helpers;

    public abstract class CoreWithLegend<V>: Core
    {
        protected List<ValueSet<V>> values;

        public Legend LegendSettings { get; set; }

        public bool DisplayLegend { get; set; }

        protected override void CheckFonts()
        {
            // Legend
            this.LegendSettings.TextStyle = this.SetupFont(this.LegendSettings.TextStyle);
        }

        protected void BuildLegend<T>(List<string> series, List<ValueSet<T>> elements, float offset = 0)
        {
            // Just exit when no series
            if (elements.Count == 0)
            {
                return;
            }

            // Initialize required variables
            Font usedFont = this.LegendSettings.TextStyle.Font;
            float width = 0;
            RectangleF longestWordSize = new RectangleF();
            foreach (string word in series)
            {
                var temp = DefaultGraphics.Instance.MeasureDisplayString(word, usedFont);
                if (temp.Width > width)
                {
                    width = temp.Width;
                    longestWordSize = temp;
                }
            }

            // Variables based on longest word size
            float colorSquareSize = longestWordSize.Height;
            float colorSquareSize125 = colorSquareSize * 1.25f;
            float colorSquareBorder = 1;

            float textPosition;
            float startPosition;
            PerformMove move;

            float moveValue = longestWordSize.Width + colorSquareSize125 + colorSquareBorder;
            switch (this.LegendSettings.Position)
            {
                case Position.MiddleRight:
                case Position.MiddleLeft:
                    startPosition = this.Border.Top + (this.Border.Height / 2f);
                    float tempPosition = startPosition
                                         - ((colorSquareSize125 * elements.Count) / 2f)
                                         + ((colorSquareSize125 - colorSquareSize) / 2f);
                    if (tempPosition > this.Border.Bottom)
                    {
                        startPosition += this.Border.Bottom - tempPosition;
                    }
                    else
                    {
                        startPosition = tempPosition;
                    }

                    break;
                case Position.BottomRight:
                case Position.BottomLeft:
                    startPosition = this.Border.Bottom - (colorSquareSize125 * elements.Count)
                                    + (colorSquareSize125 - colorSquareSize);
                    break;
                default:
                    startPosition = this.Border.Top;
                    break;
            }

            switch (this.LegendSettings.Position)
            {
                case Position.MiddleLeft:
                    textPosition = this.Border.Left - moveValue;
                    move = PerformMove.Left | PerformMove.Top | PerformMove.Bottom | PerformMove.HalfY;
                    break;
                case Position.MiddleRight:
                    textPosition = this.Border.Right + colorSquareSize125;
                    move = PerformMove.Right | PerformMove.Top | PerformMove.Bottom | PerformMove.HalfY;
                    break;
                case Position.BottomLeft:
                    textPosition = this.Border.Left - moveValue;
                    move = PerformMove.Left | PerformMove.Bottom;
                    break;
                case Position.BottomRight:
                    textPosition = this.Border.Right + colorSquareSize125;
                    move = PerformMove.Right | PerformMove.Bottom;
                    break;
                case Position.TopLeft:
                    textPosition = this.Border.Left - moveValue;
                    move = PerformMove.Left | PerformMove.Top;
                    break;
                default:
                    textPosition = this.Border.Right + colorSquareSize125;
                    move = PerformMove.Right | PerformMove.Top;
                    break;
            }

            textPosition += offset;

            for (int i = 0; i < elements.Count; i++)
            {
                IElement element = new Square(textPosition - colorSquareSize,
                    startPosition,
                    colorSquareSize,
                    new SolidBrush(elements[i].Color))
                {
                    MoveWhen = move
                };
                element.Attributes["g"] = i;
                this.AddElement(element);

                element = new ChartString(textPosition + colorSquareBorder, startPosition,
                    longestWordSize.Width,
                    colorSquareSize, elements[i].Name, this.LegendSettings.TextStyle.Font,
                    this.LegendSettings.TextStyle.ColorBrush)
                    {
                        MoveWhen = move,
                        Color = new SolidBrush(Color.Black)
                    };
                element.Attributes["g"] = i;
                this.AddElement(element);

                startPosition += colorSquareSize125;
            }

            this.ResetColor();
            switch (this.LegendSettings.Position)
            {
                case Position.TopLeft:
                case Position.MiddleLeft:
                case Position.BottomLeft:
                    this.Border.Left += moveValue + offset;
                    break;
                default:
                    this.Border.Right -= moveValue + offset;
                    break;
            }
        }

        public CoreWithLegend(Color[] possibleColors = null)
        {
            this.values = new List<ValueSet<V>>();
            this.LegendSettings = new Legend();


            string transparent = Color.Transparent.Name;
            if (possibleColors == null)
            {
                this.PossibleColors =
                    typeof(Color).GetProperties(BindingFlags.Static | BindingFlags.Public)
                        .Select(x =>
                            {
                                var temp = x.PropertyType;
                                if (temp == typeof(Color))
                                {
                                    Color color = Color.FromName(x.Name);
                                    if (!this.exludedColors.Contains(color))
                                    {
                                        return color;
                                    }
                                }
                                //todo: inny kolor
                                return Color.Transparent;
                            }).Where(x => x.Name != transparent)
                        .ToArray();
            }
        }

        protected void ResetColor()
        {
            this._currentColor = 0;
        }

        protected Color GetNextColor()
        {
            while (this._currentColor < this.PossibleColors.Length)
            {
                return this.PossibleColors[this._currentColor++];
            }

            this.ResetColor();
            return this.GetNextColor();
        }


        protected int _currentColor;

        public Color[] PossibleColors;
    }
}
